#include "qspi_flash.h"

static void QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi) {
    QSPI_CommandTypeDef qspi_cmd;
    QSPI_AutoPollingTypeDef qspi_config;

    qspi_cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    qspi_cmd.Instruction = 0x05;
    qspi_cmd.AddressMode = QSPI_ADDRESS_NONE;
    qspi_cmd.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
    qspi_cmd.DataMode = QSPI_DATA_1_LINE;
    qspi_cmd.DummyCycles = 0;
    qspi_cmd.DdrMode = QSPI_DDR_MODE_DISABLE;
    qspi_cmd.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
    qspi_cmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;

    qspi_config.Match = 0x00;
    qspi_config.Mask = 0x01;
    qspi_config.MatchMode = QSPI_MATCH_MODE_AND;
    qspi_config.StatusBytesSize = 1;
    qspi_config.Interval = 0x10;
    qspi_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;

    if (HAL_QSPI_AutoPolling(hqspi, &qspi_cmd, &qspi_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
        //Error_Handler();
    }
}

void Qspi_Flash_WriteEnable(QSPI_HandleTypeDef *hqspi) {
    QSPI_CommandTypeDef qspi_cmd;
    QSPI_AutoPollingTypeDef qspi_config;

    qspi_cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    qspi_cmd.Instruction = 0x06;
    qspi_cmd.AddressMode = QSPI_ADDRESS_NONE;
    qspi_cmd.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
    qspi_cmd.DataMode = QSPI_DATA_NONE;
    qspi_cmd.DummyCycles = 0;
    qspi_cmd.DdrMode = QSPI_DDR_MODE_DISABLE;
    qspi_cmd.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
    qspi_cmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
    if (HAL_QSPI_Command(hqspi, &qspi_cmd, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
        //Error_Handler();
    }

    qspi_config.Match = 0x02;
    qspi_config.Mask = 0x02;
    qspi_config.MatchMode = QSPI_MATCH_MODE_AND;
    qspi_config.StatusBytesSize = 1;
    qspi_config.Interval = 0x10;
    qspi_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;

    qspi_cmd.Instruction = 0x05;
    qspi_cmd.DataMode = QSPI_DATA_1_LINE;
    if (HAL_QSPI_AutoPolling(hqspi, &qspi_cmd, &qspi_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
        //Error_Handler();
    }
}

void Qspi_Flash_ReadId(QSPI_HandleTypeDef *hqspi) {
    uint8_t id[8];
    QSPI_CommandTypeDef qspi_cmd =
            {
                    .Instruction=0x90,
                    .InstructionMode=QSPI_INSTRUCTION_1_LINE,
                    .AddressMode=QSPI_ADDRESS_1_LINE,
                    .Address=0x0,
                    .AddressSize=QSPI_ADDRESS_24_BITS,
                    .AlternateByteMode=QSPI_ALTERNATE_BYTES_NONE,
                    .DataMode=QSPI_DATA_1_LINE,
                    .NbData=2,
                    .DummyCycles=0,
                    .DdrMode=QSPI_DDR_MODE_DISABLE,
                    .DdrHoldHalfCycle=QSPI_DDR_HHC_ANALOG_DELAY,
                    .SIOOMode=QSPI_SIOO_INST_EVERY_CMD
            };
    HAL_QSPI_Command(hqspi, &qspi_cmd, 1000);
    HAL_QSPI_Receive(hqspi, id, 1000);
    for(int i=0;i<100;i++);
}

void Qspi_Flash_Read(QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t ReadAddr, uint32_t Size) {
    QSPI_CommandTypeDef qspi_cmd =
            {
                    .Instruction=0x03,
                    .InstructionMode=QSPI_INSTRUCTION_1_LINE,
                    .AddressMode=QSPI_ADDRESS_1_LINE,
                    .Address=ReadAddr,
                    .AddressSize=QSPI_ADDRESS_32_BITS,
                    .AlternateByteMode=QSPI_ALTERNATE_BYTES_NONE,
                    .DataMode=QSPI_DATA_1_LINE,
                    .NbData=Size,
                    .DummyCycles=0,
                    .DdrMode=QSPI_DDR_MODE_DISABLE,
                    .DdrHoldHalfCycle=QSPI_DDR_HHC_ANALOG_DELAY,
                    .SIOOMode=QSPI_SIOO_INST_EVERY_CMD
            };
    HAL_QSPI_Command(hqspi, &qspi_cmd, 1000);
    HAL_QSPI_Receive(hqspi, pData, 1000);
}

void Qspi_Flash_Erase(QSPI_HandleTypeDef *hqspi, uint32_t address) {
    QSPI_CommandTypeDef qspi_cmd;
    qspi_cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    qspi_cmd.AddressSize = QSPI_ADDRESS_24_BITS;
    qspi_cmd.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
    qspi_cmd.DdrMode = QSPI_DDR_MODE_DISABLE;
    qspi_cmd.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
    qspi_cmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
    qspi_cmd.Instruction = 0xD8;
    qspi_cmd.AddressMode = QSPI_ADDRESS_1_LINE;
    qspi_cmd.Address = address;
    qspi_cmd.DataMode = QSPI_DATA_NONE;
    qspi_cmd.DummyCycles = 0;
    Qspi_Flash_WriteEnable(hqspi);
    if (HAL_QSPI_Command(hqspi, &qspi_cmd, 1000) != HAL_OK) {
        //Error_Handler();
    }
    QSPI_AutoPollingMemReady(hqspi);
}

void Qspi_Flash_Write(QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t WriteAddr, uint32_t Size) {
    QSPI_CommandTypeDef qspi_cmd;
    qspi_cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    qspi_cmd.AddressSize = QSPI_ADDRESS_24_BITS;
    qspi_cmd.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
    qspi_cmd.DdrMode = QSPI_DDR_MODE_DISABLE;
    qspi_cmd.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
    qspi_cmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;

    Qspi_Flash_WriteEnable(hqspi);

    qspi_cmd.Instruction = 0xD8;
    qspi_cmd.AddressMode = QSPI_ADDRESS_1_LINE;
    qspi_cmd.Address = WriteAddr;
    qspi_cmd.DataMode = QSPI_DATA_NONE;
    qspi_cmd.DummyCycles = 0;
    if (HAL_QSPI_Command(hqspi, &qspi_cmd, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
        //Error_Handler();
    }
    QSPI_AutoPollingMemReady(hqspi);

    Qspi_Flash_WriteEnable(hqspi);

    qspi_cmd.Instruction = 0x32;
    qspi_cmd.AddressMode = QSPI_ADDRESS_1_LINE;
    qspi_cmd.DataMode = QSPI_DATA_4_LINES;
    qspi_cmd.NbData = Size;
    if (HAL_QSPI_Command(hqspi, &qspi_cmd, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
        //Error_Handler();
    }
    if (HAL_QSPI_Transmit(hqspi, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
        //Error_Handler();
    }
    QSPI_AutoPollingMemReady(hqspi);
}